package Logic

import (
	"errors"
	"fmt"
	"github.com/golang-jwt/jwt"
	"time"
	"yz-go/Common"
	"yz-go/Models"
)

type MyClaims struct {
	Id       int    `json:"id"`
	Username string `json:"username"`
	Password string `json:"password"`
	jwt.StandardClaims
}

type userinfo struct {
	Id int
}

const TokenExpireDuration = time.Hour * 24

// GenToken 生成JWT
func HandleToken(username, password string) (res Common.ResData) {
	// 数据库验证 俩种方法都可以
	//List := models.Demo{}
	List := userinfo{}
	//result := models.DB.Where("username=? and password=?", username, password).Find(&List)
	result := Models.GINBLOGDB.Table("demo").Where("username=? and password=?", username, password).Find(&List)

	fmt.Printf("result:%+v", result)
	fmt.Printf("result:%+v", List)

	if result.Error != nil {
		res.Code = Common.ERROR
		res.Msg = "尚未认证数据"
		return res
	}

	// 创建一个我们自己的声明。可以用new来实例这个结构体，new后是保存在堆内存中 需要手动释放内存，而直接初始化的可以自动释放内存
	// make 只能用于 map 、slice 、channel ，new 只能用于结构体
	// new(T) 会为 T 类型的新值分配已置零的内存空间，并返回地址（指针），即类型为 *T的值。换句话说就是，返回一个指针，该指针指向新分配的、类型为 T 的零值。适用于值类型，如数组、结构体等。
	// make(T,args) 返回初始化之后的 T 类型的值，这个值并不是 T 类型的零值，也不是指针 *T，是经过初始化之后的 T 的引用。make() 只适用于 slice、map 和 channel.

	//返回类型不同：直接初始化结构体变量返回的是结构体变量本身，而使用 new 函数创建结构体变量返回的是该结构体变量的指针。
	//内存分配位置不同：直接初始化结构体变量时，变量的值会被分配在栈内存中，在作用域结束后，该内存会自动释放；而使用 new 函数创建结构体变量时，变量的值会被分配在堆内存中，需要手动释放内存避免造成内存泄漏。
	//初始化方式不同：直接初始化结构体变量时，需要按字段定义的顺序逐一为每个字段赋值；而使用 new 函数创建结构体变量时，可以使用结构体字面量或者逐个赋值的方式来初始化每个字段。
	//使用 new 函数创建结构体变量可以确保所有字段都被初始化为默认值，而直接初始化结构体变量时需要手动初始化每个字段。
	info := MyClaims{
		List.Id,
		username, // 自定义字段
		password,
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
			Issuer:    "my-project",                               // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, info)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	var tmp string
	var err error
	tmp, err = token.SignedString(Common.MYSECRET)

	if err != nil {
		res.Code = Common.ERROR
		res.Msg = "token  失败"
		return res
	}

	res.Code = Common.SUCCESS
	res.Msg = "success"
	res.Data = Common.ResDataToken{Token: tmp}
	return res
}

// ParseToken 解析JWT
func ParseToken(tokenString string) (*MyClaims, error) {

	fmt.Println("=====解析token=====")
	fmt.Println(tokenString)

	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
		return Common.MYSECRET, nil
	})
	if err != nil {
		return nil, err
	}
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校验token
		return claims, nil
	}
	return nil, errors.New("invalid token")
}
